#ifndef _OBJECT_POOL_HPP_20120407
#define _OBJECT_POOL_HPP_20120407

#include "base.hpp"
#include "memory_pool.hpp"

namespace mina
{
	template <typename _T>
		class ObjectPool
		{
			public :
				ObjectPool(int obj_num);
				~ObjectPool();

				void destroy(_T & pObj);

				_T * construct();

				template <typename _P1>
					_T * construct(_P1 & p1);

				template <typename _P1, typename _P2>
					_T * construct(_P1 & p1, _P2 & p2);

				template <typename _P1, typename _P2, typename _P3>
					_T * construct(_P1 & p1, _P2 & p2, _P3 & p3);

				template <typename _P1, typename _P2, typename _P3, typename _P4>
					_T * construct(_P1 & p1, _P2 & p2, _P3 & p3, _P4 & p4);

				bool empty() { return _alloc.empty(); }
				int  free_block() { return _alloc.free_block(); }

			public :
				MemoryPool  _alloc;
		};

	template <typename _T>
		ObjectPool<_T>::ObjectPool(int obj_num)
		: _alloc(sizeof(_T), obj_num * sizeof(_T))
		{
		}

	template <typename _T>
		ObjectPool<_T>::~ObjectPool()
		{
		}

	template <typename _T>
		void ObjectPool<_T>::destroy(_T & pObj)
		{
			pObj.~_T();
			_alloc.deallocate((void*)&pObj);
		}

	template <typename _T>
		_T * ObjectPool<_T>::construct()
		{
			void * addr = _alloc.allocate();

			if (NULL != addr)
			{
				new (addr) _T;
			}

			return (_T*)addr;
		}

	template <typename _T>
		template <typename _P1>
		_T * ObjectPool<_T>::construct(_P1 & p1)
		{
			void * addr = _alloc.allocate();

			if (NULL != addr)
			{
				new (addr) _T(p1);
			}

			return (_T*)addr;
		}

	template <typename _T>
		template <typename _P1, typename _P2>
		_T * ObjectPool<_T>::construct(_P1 & p1, _P2 & p2)
		{
			void * addr = _alloc.allocate();

			if (NULL != addr)
			{
				new (addr) _T(p1, p2);
			}

			return (_T*)addr;
		}

	template <typename _T>
		template <typename _P1, typename _P2, typename _P3>
		_T * ObjectPool<_T>::construct(_P1 & p1, _P2 & p2, _P3 & p3)
		{
			void * addr = _alloc.allocate();

			if (NULL != addr)
			{
				new (addr) _T(p1, p2, p3);
			}

			return (_T*)addr;
		}

	template <typename _T>
		template <typename _P1, typename _P2, typename _P3, typename _P4>
		_T * ObjectPool<_T>::construct(_P1 & p1, _P2 & p2, _P3 & p3, _P4 & p4)
		{
			void * addr = _alloc.allocate();

			if (NULL != addr)
			{
				new (addr) _T(p1, p2, p3, p4);
			}

			return (_T*)addr;
		}

}

#endif

